/************************************************************************
Copyright (c) 2010, 2013, C.R. All rights reserved. 

E-mail: crtoyou@gmail.com; crtoyou@163.com

You can redistribute it and/or modify it under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation version 3 of the License.

This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. if not, write to the Free Software Foundation, Inc., 
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
************************************************************************/

#ifndef __CR_IOCP_PORT_BASE_H__
#define __CR_IOCP_PORT_BASE_H__

#include <criocp.h>
#include <crsocket.h>
#include <crpool.h>
#include <crpacket.h>
#include <crdebug.h>
#include <Windows.h>
#pragma comment(lib, "Winmm.lib")

//////////////////////////////////////////////////////////////////////////
//enum {
//	KEEPALIVETIME = 5*60*1000,
//	KEEPALIVEINTERVAL = 2*1000,
//	LINGERTIME = 30*1000
//};
//tcp_s_wrapper_t::setkeepalive(s, TRUE, KEEPALIVETIME, KEEPALIVEINTERVAL);
//tcp_s_wrapper_t::setreuse(s, TRUE);
//tcp_s_wrapper_t::setlinger(s, LINGERTIME);
//////////////////////////////////////////////////////////////////////////

namespace criocp {

using namespace cr;

struct OVERLAPPEDEX : OVERLAPPED
{
	ULONG len;
	CHAR* buf;
	HANDLE handle;
	DWORD flag;
};

// this base may be used for file I/O or other completion operations. 
template <
	typename type_ovlp_ex = OVERLAPPEDEX
>
class CIocpPortBase 
	: public IIocpPortBase
{
public:
	struct event_wrapper_t // all members are static for handlepool
	{
		typedef WSAEVENT handle_t;
		static inline WSAEVENT create() {return WSACreateEvent();}
		static inline void close(WSAEVENT h) {WSACloseEvent(h);}
		static inline WSAEVENT invalid_handle() {return WSA_INVALID_EVENT;}
		static inline bool is_valid(WSAEVENT h) {return h!=WSA_INVALID_EVENT;}
	};
	objpool<event_wrapper_t> m_poolEvent;
	objpool<simple_wrapper_t<type_ovlp_ex>> m_poolOvlp;
	memgroup<> m_mem;

public:
	inline type_ovlp_ex* LeaseOvlp()
	{
		type_ovlp_ex* ovlp = m_poolOvlp.lease_s();
		if (!ovlp)
			return NULL;
		ZeroMemory(ovlp, sizeof(type_ovlp_ex));
		ovlp->hEvent = m_poolEvent.lease_s();
		if (!event_wrapper_t::is_valid(ovlp->hEvent)) {
			ReleaseOvlp(ovlp);
			return NULL;
		}
		return ovlp;
	}

	inline void ReleaseOvlp(type_ovlp_ex* ovlp)
	{
		if (!ovlp)
			return;
		m_poolEvent.release_s(ovlp->hEvent);
		m_poolOvlp.release_s(ovlp);
	}

protected:
	virtual ~CIocpPortBase()
	{
		singleton<CIocpCore> theIocp;
		theIocp().DetachPort(this);
	}

	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		ASSERT(lpOvlp);
		type_ovlp_ex* ovlp = (type_ovlp_ex*)lpOvlp;
		ASSERT(PROMPT(_T("none handled op: %x"), ovlp->flag));
	}

	virtual void OnIocpTimeout(DWORD timeout)
	{
		TRACE(_T("CIocpPortBase::OnIocpTimeout() called.\n"));
	}
};


class CIocpFileBase 
	: public CIocpPortBase<>
{
protected:
	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		__super::OnIoCompletion(dwBytes, lpOvlp, dwErr);
	}
};


template <
	typename type_packhead = packhead0_t,
	size_t PERMIT_SIZE = 0,
class type_ovlp_ex = OVERLAPPEDEX
>
class CIocpSocketBase 
	: public CIocpPortBase<type_ovlp_ex>
	, public CBaseSocket
	, public __wsa_ex_functions__
{
public:
	enum // overlapped operation
	{
		OVLP_OP_NOOP = 0x0,	// no operation
		OVLP_OP_ACPT = 0x1,	// accept
		OVLP_OP_CNCT = 0x2,	// connect
		OVLP_OP_DSCN = 0x3,	// disconnect
		OVLP_OP_PEEK = 0x4,	// peek head
		OVLP_OP_RECV = 0x5,	// recv packet
		OVLP_OP_SEND = 0x6,	// send packet
		OVLP_OP_MASK = 0x7, // mask of operations in flag 
	};
	// for memory pool(s)
	enum {
		ADDR_PERMIT_SIZE = PERMIT_SIZE + 2 * sizeof(sockaddr) + 32
	};

	typedef pack_t<type_packhead> pack_t;

public:
	mempool<ADDR_PERMIT_SIZE> m_poolPermit;

public:
	virtual void SuggestInit()
	{
		enum { PERMIT_COUNT = 1024-1 };
		enum {
			//adjust these count by statistics report 
			MINI_COUNT = 1024/4,   //4K
			TINY_COUNT = 1024*1-1, //64K
			SMAL_COUNT = 1024*2-1, //1M
			NORM_COUNT = 1024*8-1, //8M
			HUGE_COUNT = 1024/4,   //1M
			PEEK_COUNT = MINI_COUNT+TINY_COUNT+SMAL_COUNT+NORM_COUNT+HUGE_COUNT
		};
		//enum {
		//	MINI_SIZE = 8,        //8
		//	TINY_SIZE = 1024/16,  //64
		//	SMAL_SIZE = 1024/2,   //512
		//	NORM_SIZE = 1024*1,   //1024
		//	HUGE_SIZE = 1024*4,   //4096
		//	MUCH_SIZE = 1*1024*1024*1024 //4G
		//};
		m_mem.init(MINI_COUNT+PEEK_COUNT, TINY_COUNT, SMAL_COUNT, NORM_COUNT, HUGE_COUNT);
		m_poolPermit.init(PERMIT_COUNT);
	}

protected:
	int PostDisconnect(SOCKET s)
	{
		ASSERT(INVALID_SOCKET != s);
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp)
			return -1;
		ovlp->buf = NULL;
		ovlp->len = 0;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_DSCN;
		if (!CR_DisconnectEx(s, ovlp, TF_REUSE_SOCKET, 0)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

	int PostPeekHead(SOCKET s)
	{
		ASSERT(INVALID_SOCKET != s);
		type_packhead* head = (type_packhead*)
			m_mem.lease_s(offsetof(pack_t, payload));
		if (!head)
			return -1;
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp) {
			m_mem.release_s((char*)head);
			return -1;
		}
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_PEEK;
		ovlp->len = offsetof(pack_t, payload);
		ovlp->buf = (CHAR*)head;
		WSABUF buf[1];
		buf[0].len = ovlp->len;
		buf[0].buf = ovlp->buf;
		DWORD msg_flag = MSG_PEEK; //peek mode
		DWORD dwBytes = 0;
		if (SOCKET_ERROR == WSARecv(s, &buf[0], 1, &dwBytes, &msg_flag, ovlp, 0)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

	int PostWSARecv(SOCKET s, char* buffer, int len) 
	{
		ASSERT(INVALID_SOCKET != s);
		if (!buffer || len <= 0)
			return -1;
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp)
			return -1;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_RECV;
		ovlp->buf = buffer;
		ovlp->len = len;
		WSABUF buf[1];
		buf[0].len = ovlp->len;
		buf[0].buf = ovlp->buf;
		DWORD dwBytes = 0;
		DWORD msg_flag = 0;
		if (SOCKET_ERROR == WSARecv(s, &buf[0], 1, &dwBytes, &msg_flag, ovlp, 0)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			m_mem.release_s(ovlp->buf);
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

	//be sure the extern buffer keeps valid until sent complete. 
	//it will be released by completion routing. 
	int PostWSASend(SOCKET s, char* buffer, int len)
	{
		ASSERT(INVALID_SOCKET != s);
		if (!buffer || len <= 0)
			return -1;
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp)
			return -1;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_SEND;
		ovlp->buf = buffer;
		ovlp->len = len;
		WSABUF buf[1];
		buf[0].len = ovlp->len;
		buf[0].buf = ovlp->buf;
		DWORD dwBytes = 0;
		DWORD msg_flag = 0;
		if (SOCKET_ERROR == WSASend(s, &buf[0], 1, &dwBytes, msg_flag, ovlp, 0)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			m_mem.release_s(ovlp->buf);
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

protected:
	virtual int OnWSAError(SOCKET s, int err, type_ovlp_ex* ovlp = NULL)
	{
		switch (err)
		{
		case WSA_IO_PENDING:
			break;
			// TODO: case other. 
		default:
			if (ovlp) {
				static const TCHAR* ovlp_op_name[] = {
					_T("OVLP_OP_NOOP"), 
					_T("OVLP_OP_ACPT"), 
					_T("OVLP_OP_CNCT"), 
					_T("OVLP_OP_DSCN"), 
					_T("OVLP_OP_PEEK"), 
					_T("OVLP_OP_RECV"), 
					_T("OVLP_OP_SEND"), 
					_T("OVLP_OP_MASK")
				};
				ASSERT(PROMPT(_T("operation %s failed err %d.\n"),
					ovlp_op_name[ovlp->flag & OVLP_OP_MASK], err));
			}
			return SOCKET_ERROR;
		}
		return 0;
	}

	virtual void OnDisconnected(SOCKET s)
	{}

	virtual void OnDataArrive(SOCKET s, pack_t* pack, void* payload, size_t loadlen)
	{}

	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		ASSERT(lpOvlp);
		type_ovlp_ex* ovlp = (type_ovlp_ex*)lpOvlp;
		switch (ovlp->flag & OVLP_OP_MASK)
		{
			//case OVLP_OP_NOOP:
			//	TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_NOOP)\n"));
			//	break;
			//case OVLP_OP_ACPT:
			//	TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_ACPT)\n"));
			//	break;
			//case OVLP_OP_CNCT:
			//	TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_CNCT)\n"));
			//	break;
		case OVLP_OP_DSCN:
			TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_DSCN)\n"));
			{
				ASSERT(!ovlp->buf);
				OnDisconnected((SOCKET)ovlp->handle);
				ReleaseOvlp(ovlp);
			}
			break;
		case OVLP_OP_PEEK:
			TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_PEEK)\n"));
			{
				if (dwErr) {
					PostDisconnect((SOCKET)ovlp->handle);
					break;
				}
				ASSERT(ovlp->buf);
				type_packhead* head = (type_packhead*)(ovlp->buf);
				uint32 packsize = head->len;
				ASSERT(packsize <= type_packhead::max_len);
				if (packsize > type_packhead::max_len)
					return;
				char* pMem = m_mem.lease_s(packsize);
				PostWSARecv((SOCKET)ovlp->handle, pMem, packsize);
				m_mem.release_s((char*)head);
				ReleaseOvlp(ovlp);
			}
			break;
		case OVLP_OP_RECV:
			TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_RECV)\n"));
			{
				if (dwErr) {
					PostDisconnect((SOCKET)ovlp->handle);
					break;
				}
				PostPeekHead((SOCKET)ovlp->handle);
				ASSERT(ovlp->buf);
				pack_t* pack = (pack_t*)ovlp->buf;
				void* payload;
				size_t loadlen;
				cr::unpack<type_packhead>(pack, payload, loadlen);
				OnDataArrive((SOCKET)ovlp->handle, pack, payload, loadlen);
				m_mem.release_s(ovlp->buf);
				ReleaseOvlp(ovlp);
			}
			break;
		case OVLP_OP_SEND:
			TRACE(_T("CIocpSocketBase::OnIoCompletion(OVLP_OP_SEND)\n"));
			{
				if (dwErr) {
					PostDisconnect((SOCKET)ovlp->handle);
					break;
				}
				ASSERT(ovlp->buf);
				m_mem.release_s(ovlp->buf);
				ReleaseOvlp(ovlp);
			}
			break;
		default:
			TRACE(_T("CIocpSocketBase::OnIoCompletion(default)\n"));
			__super::OnIoCompletion(dwBytes, lpOvlp, dwErr);
		}
	}
};


template <
	typename type_packhead = packhead0_t, 
	size_t PERMIT_SIZE = 0, 
class type_ovlp_ex = OVERLAPPEDEX
>
class CIocpClientBase 
	: public CIocpSocketBase<type_packhead, PERMIT_SIZE, type_ovlp_ex>
{
private:
	//disable the direct call without permit info. 
	int Connect(const char* RemoteIp, unsigned short RemotePort);
	int Connect(const sockaddr* sa, int salen);
public:
	int Connect(const char* RemoteIp, unsigned short RemotePort, const char* permit)
	{
		sockaddr_in sin;
		sin.sin_family = AF_INET;
		sin.sin_addr.s_addr = inet_addr(RemoteIp);
		sin.sin_port = htons(RemotePort);
		return Connect((sockaddr*)&sin, sizeof(sockaddr), permit);
	}
	int Connect(sockaddr* sa, int salen, const char* permit)
	{
		singleton<CIocpCore> theIocp;
		theIocp().BindHandle((HANDLE)SafeHandle(), this);
		return PostConnect(SafeHandle(), sa, salen, permit);
	}

	int Disconnect()
	{
		return PostDisconnect(SafeHandle());
	}

protected:
	int PostConnect(SOCKET s, sockaddr* sa, int salen, const char* permit)
	{
		ASSERT(INVALID_SOCKET != s);
		char* buf = m_poolPermit.lease_s();
		if (!buf)
			return -1;
		if (permit)
			memcpy(buf, permit, PERMIT_SIZE);
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp){
			m_poolPermit.release_s(buf);
			return -1;
		}
		ovlp->len = PERMIT_SIZE;
		ovlp->buf = buf;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_CNCT;
		DWORD dwBytes;
		if (!CR_ConnectEx(s, sa, salen, buf, PERMIT_SIZE, &dwBytes, (LPOVERLAPPED)ovlp)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			m_poolPermit.release_s(ovlp->buf);
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

protected:
	virtual void OnConnectError(SOCKET s, DWORD dwErr, const char* permit = NULL)
	{
		switch (dwErr)
		{
		case 0:
			break;
			//TODO: case other err prompt. 
		default:
			ASSERT(PROMPT(_T("err:%d"), dwErr));
		}
	}

	virtual void OnConnected(SOCKET s, const char* permit = NULL)
	{
		PostPeekHead(s);
	}

	virtual void OnDisconnected(SOCKET s)
	{
		ASSERT(PROMPT(_T("CIocpClientBase::OnDisconnected(s)")));
	}

	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		ASSERT(lpOvlp);
		type_ovlp_ex* ovlp = (type_ovlp_ex*)lpOvlp;
		switch (ovlp->flag & OVLP_OP_MASK)
		{
			//case OVLP_OP_NOOP:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_NOOP)\n"));
			//	break;
			//case OVLP_OP_ACPT:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_ACPT)\n"));
			//	break;
		case OVLP_OP_CNCT:
			TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_CNCT)\n"));
			{
				if (0 != dwErr)
					OnConnectError((SOCKET)ovlp->handle, dwErr, ovlp->buf);
				else
					OnConnected((SOCKET)ovlp->handle, ovlp->buf);
				m_poolPermit.release_s(ovlp->buf);
				ReleaseOvlp(ovlp);
			}
			break;
			//case OVLP_OP_DSCN:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_DSCN)\n"));
			//	break;
			//case OVLP_OP_PEEK:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_PEEK)\n"));
			//	break;
			//case OVLP_OP_RECV:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_RECV)\n"));
			//	break;
			//case OVLP_OP_SEND:
			//	TRACE(_T("CIocpClientBase::OnIoCompletion(OVLP_OP_SEND)\n"));
			//	break;
		default:
			TRACE(_T("CIocpClientBase::OnIoCompletion(default)\n"));
			__super::OnIoCompletion(dwBytes, lpOvlp, dwErr);
		}
	}
};


template <
	typename type_packhead = packhead0_t,
	size_t PERMIT_SIZE = 0,
	typename type_ovlp_ex = OVERLAPPEDEX
>
class CIocpServerBase 
	: public CIocpSocketBase<type_packhead, PERMIT_SIZE, type_ovlp_ex>
{
public:
	struct tcp_s_wrapper_t // all members are static for handlepool
	{
		typedef SOCKET handle_t;
		static inline SOCKET create()
		{
			SOCKET s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
			setreuse(s, TRUE);
			return s;
		}
		static inline void close(SOCKET h)
		{ closesocket(h); }
		static inline SOCKET invalid_handle()
		{ return INVALID_SOCKET; }
		static inline bool is_valid(SOCKET h)
		{ return h != INVALID_SOCKET; }
		static inline bool setkeepalive(SOCKET s, BOOL enable, u_long livetime, u_long interval)
		{
			tcp_keepalive alive_in = {0};
			tcp_keepalive alive_out = {0};
			alive_in.onoff = enable;
			alive_in.keepalivetime = livetime;
			alive_in.keepaliveinterval = interval;
			unsigned long ulret = 0;
			return (!setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&enable, sizeof(enable))
				&& !WSAIoctl(s, SIO_KEEPALIVE_VALS, &alive_in, sizeof(alive_in),
				&alive_out, sizeof(alive_out), &ulret, NULL, NULL));
		}
		static inline bool setlinger(SOCKET s, u_long lingertime)
		{
			linger lg;
			lg.l_onoff = TRUE;
			lg.l_linger = lingertime;
			return (!setsockopt(s, SOL_SOCKET, SO_LINGER, (char*)&lg, sizeof(lg)));
		}
		static inline bool setreuse(SOCKET s, BOOL enable)
		{
			return (!setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&enable, sizeof(enable)));
		}
	};
	objpool<tcp_s_wrapper_t> m_poolSock;

public:
	int Listen(int backlog = 5)
	{
		if (0 != CBaseSocket::Listen(backlog))
			return -1;
		singleton<CIocpCore> theIocp;
		if (!theIocp().BindHandle((HANDLE)SafeHandle(), this))
			return -1;
		for (int i=0; i<backlog; ++i) {
			SOCKET s = m_poolSock.lease_s();
			if (INVALID_SOCKET == s)
				return -1;
			if (!theIocp().BindHandle((HANDLE)s, this)
				|| 0 != PostAccept(s))
			{
				return -1;
			}
		}
		return 0;
	}

protected:
	int PostAccept(SOCKET s)
	{
		ASSERT(INVALID_SOCKET != s);
		printf("post accept for socket:%d\n", s);
		char* permit = m_poolPermit.lease_s();
		if (!permit)
			return -1;
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp) {
			m_poolPermit.release_s(permit);
			return -1;
		}
		ovlp->len = ADDR_PERMIT_SIZE;
		ovlp->buf = (CHAR*)permit;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_ACPT;
		DWORD dwBytes = 0;
		if (!CR_AcceptEx(SafeHandle(), s, ovlp->buf, PERMIT_SIZE, 
			sizeof(sockaddr)+16, sizeof(sockaddr)+16, &dwBytes, ovlp)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			m_poolPermit.release_s(ovlp->buf);
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

protected:
	virtual void CheckAddress(SOCKET s, in_addr sin_addr)
	{
		OnAddressAccept(s, sin_addr);
	}

	virtual void OnAddressAccept(SOCKET s, in_addr sin_addr)
	{}

	virtual void OnAddressReject(SOCKET s, in_addr sin_addr)
	{}

	virtual void CheckPermit(SOCKET s, const char* permit)
	{
		ASSERT(permit);
		OnPermitAccept(s, permit);
	}

	virtual void OnPermitAccept(SOCKET s, const char* permit)
	{
		ASSERT(permit);
		PostPeekHead(s);
	}

	virtual void OnPermitReject(SOCKET s, const char* permit)
	{
		ASSERT(permit);
		PostDisconnect(s); 
	}

	virtual void OnDisconnected(SOCKET s)
	{
		m_poolSock.release_s(s);
	}

	virtual int OnWSAError(SOCKET s, int err, type_ovlp_ex* ovlp = NULL)
	{
		if (WSA_INVALID_HANDLE == err) {
			m_poolSock.release_s(m_poolSock.recreate_s(s));
		}
		return __super::OnWSAError(s, err, ovlp);
	}

	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		ASSERT(lpOvlp);
		type_ovlp_ex* ovlp = (type_ovlp_ex*)lpOvlp;
		switch (ovlp->flag & OVLP_OP_MASK)
		{
			//case OVLP_OP_NOOP:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_NOOP)\n"));
			//	break;
		case OVLP_OP_ACPT:
			TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_ACPT)\n"));
			{
				SOCKET s = m_poolSock.lease_s();
				if (INVALID_SOCKET != s)
					PostAccept(s);
				ASSERT(ovlp->buf && ovlp->len >= ADDR_PERMIT_SIZE);
				sockaddr_in *host, *peer;
				INT hostlen = sizeof(sockaddr), peerlen = sizeof(sockaddr);
				CR_GetAcceptExSockaddrs(ovlp->buf, PERMIT_SIZE, hostlen+16, peerlen+16, 
					(sockaddr**)&host, &hostlen, (sockaddr**)&peer, &peerlen);
				const char* permit = ovlp->buf;
				CheckAddress((SOCKET)ovlp->handle, peer->sin_addr); 
				CheckPermit((SOCKET)ovlp->handle, permit);
				m_poolPermit.release_s(ovlp->buf);
				ReleaseOvlp(ovlp);
			}
			break;
			//case OVLP_OP_CNCT:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_CNCT)\n"));
			//	break;
			//case OVLP_OP_DSCN:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_DSCN)\n"));
			//	break;
			//case OVLP_OP_PEEK:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_PEEK)\n"));
			//	break;
			//case OVLP_OP_RECV:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_RECV)\n"));
			//	break;
			//case OVLP_OP_SEND:
			//	TRACE(_T("CIocpServerBase::OnIoCompletion(OVLP_OP_SEND)\n"));
			//	break;
		default: 
			TRACE(_T("CIocpServerBase::OnIoCompletion(default)\n"));
			__super::OnIoCompletion(dwBytes, lpOvlp, dwErr);
		}
	}

	virtual void OnIocpTimeout(DWORD timeout)
	{
		//test the listen port, in case no half socket in waiting. 
		sockaddr sa;
		int len = sizeof(sa);
		getsockname(SafeHandle(), &sa, &len);
		CBaseSocket stest;
		stest.Create();
		TRACE(_T("test connect self.\n"));
		if (0 != stest.Connect(&sa, len)) {
			TRACE(_T("test connect failed, no socket waiting for connection. \n"));
			//no socket is waiting. 
			//replenish the count of socket waiting. 
			SOCKET s = m_poolSock.lease_s();
			if (INVALID_SOCKET != s)
				PostAccept(s);
			TRACE(_T("replenish the count of socket waiting. \n"));
		}
		stest.Close();
		__super::OnIocpTimeout(timeout);
	}
};


//////////////////////////////////////////////////////////////////////////
//CIocpDomainBase, for multi-multi connections. 

template <
	typename type_packhead = packhead0_t,
	size_t PERMIT_SIZE = 0,
	typename type_ovlp_ex = OVERLAPPEDEX
>
class CIocpDomainBase
	: public CIocpServerBase<type_packhead, PERMIT_SIZE, type_ovlp_ex>
{
private:
	//disable the direct call without permit info. 
	int Connect(const char* RemoteIp, unsigned short RemotePort);
	int Connect(const sockaddr* sa, int salen);
public:
	int Connect(const char* RemoteIp, unsigned short RemotePort, const char* permit)
	{
		sockaddr_in sin;
		sin.sin_family = AF_INET;
		sin.sin_addr.s_addr = inet_addr(RemoteIp);
		sin.sin_port = htons(RemotePort);
		return Connect((sockaddr*)&sin, sizeof(sockaddr), permit);
	}
	int Connect(sockaddr* sa, int salen, const char* permit)
	{
		SOCKET s = m_poolSock.lease_s(); 
		sockaddr_in sin;
		int sinlen = sizeof(sin);
		//the host port must set to be reused
		getsockname(SafeHandle(), (sockaddr*)&sin, &sinlen);
		if (SOCKET_ERROR == bind(s, (sockaddr*)&sin, sizeof(sin)))
		{
			DWORD err = WSAGetLastError();
			m_poolSock.release_s(s);
			return INVALID_SOCKET;
		}
		//bind to iocp. 
		singleton<CIocpCore> theIocp;
		if (!theIocp().BindHandle((HANDLE)s, this))
			return -1;
		return PostConnect(s, sa, salen, permit);
	}

	int Disconnect(SOCKET s)
	{
		return PostDisconnect(s);
	}

protected:
	int PostConnect(SOCKET s, sockaddr* sa, int salen, const char* permit)
	{
		ASSERT(INVALID_SOCKET != s);
		char* buf = m_poolPermit.lease_s();
		if (!buf)
			return -1;
		if (permit)
			memcpy(buf, permit, PERMIT_SIZE);
		type_ovlp_ex* ovlp = LeaseOvlp();
		if (!ovlp){
			m_poolPermit.release_s(buf);
			return -1;
		}
		ovlp->len = PERMIT_SIZE;
		ovlp->buf = buf;
		ovlp->handle = (HANDLE)s;
		ovlp->flag = OVLP_OP_CNCT;
		DWORD dwBytes;
		if (!CR_ConnectEx(s, sa, salen, buf, PERMIT_SIZE, &dwBytes, (LPOVERLAPPED)ovlp)
			&& SOCKET_ERROR == OnWSAError(s, WSAGetLastError(), ovlp))
		{
			m_poolPermit.release_s(ovlp->buf);
			ReleaseOvlp(ovlp);
			return -1;
		}
		return 0;
	}

protected:
	virtual void OnConnectError(SOCKET s, DWORD dwErr, const char* permit = NULL)
	{
		switch (dwErr)
		{
		case 0:
			break;
			//TODO: case other err prompt. 
		default:
			ASSERT(PROMPT(_T("err:%d"), dwErr));
		}
	}

	virtual void OnConnected(SOCKET s, const char* permit = NULL)
	{
		PostPeekHead(s);
	}

	virtual void OnDisconnected(SOCKET s)
	{
		m_poolSock.release_s(s);
		ASSERT(PROMPT(_T("CIocpDomainBase::OnDisconnected(s)")));
	}

	virtual void OnIoCompletion(DWORD dwBytes, LPOVERLAPPED lpOvlp, DWORD dwErr)
	{
		ASSERT(lpOvlp);
		type_ovlp_ex* ovlp = (type_ovlp_ex*)lpOvlp;
		switch (ovlp->flag & OVLP_OP_MASK)
		{
			//case OVLP_OP_NOOP:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_NOOP)\n"));
			//	break;
			//case OVLP_OP_ACPT:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_ACPT)\n"));
			//	break;
		case OVLP_OP_CNCT:
			TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_CNCT)\n"));
			{
				if (0 != dwErr)
					OnConnectError((SOCKET)ovlp->handle, dwErr, ovlp->buf);
				else
					OnConnected((SOCKET)ovlp->handle, ovlp->buf);
				m_poolPermit.release_s(ovlp->buf);
				ReleaseOvlp(ovlp);
			}
			break;
			//case OVLP_OP_DSCN:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_DSCN)\n"));
			//	break;
			//case OVLP_OP_PEEK:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_PEEK)\n"));
			//	break;
			//case OVLP_OP_RECV:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_RECV)\n"));
			//	break;
			//case OVLP_OP_SEND:
			//	TRACE(_T("CIocpDomainBase::OnIoCompletion(OVLP_OP_SEND)\n"));
			//	break;
		default:
			TRACE(_T("CIocpDomainBase::OnIoCompletion(default)\n"));
			__super::OnIoCompletion(dwBytes, lpOvlp, dwErr);
		}
	}
};

}//namespace

#endif //__CR_IOCP_PORT_BASE_H__